package com.game.modular.game.playerInfo.service;

import com.game.comment.exection.ServiceException;
import com.game.modular.game.playerAssets.domain.PlayerHero;
import com.game.modular.game.playerAssets.domain.PlayerSkill;
import com.game.modular.game.playerAssets.domain.PlayerBag;
import com.game.modular.game.playerAssets.service.PlayerBagServiceImpl;
import com.game.modular.game.playerAssets.service.PlayerSkillServiceImpl;
import com.game.modular.game.playerAssets.service.PlayerHeroServiceImpl;
import com.game.modular.gameCore.drawCards.domain.CoreDraw;
import com.game.modular.gameCore.drawCards.domain.CoreDrawConfig;
import com.game.modular.gameCore.drawCards.domain.CoreDrawPool;
import com.game.modular.gameCore.drawCards.service.impl.CoreDrawConfigServiceImpl;
import com.game.modular.gameCore.drawCards.service.impl.CoreDrawPoolServiceImpl;
import com.game.modular.gameCore.drawCards.service.impl.CoreDrawServiceImpl;
import lombok.extern.slf4j.Slf4j;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.game.modular.game.playerInfo.mapper.PlayerDrawMapper;
import com.game.modular.game.playerInfo.domain.PlayerDraw;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.Resource;

/**
 * 玩家抽卡信息(PlayerDraw)表服务实现类
 *
 * @author cxy
 * @since 2024-08-08 10:42:41
 */
@Slf4j
@Service
public class PlayerDrawServiceImpl {
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;
    @Resource
    private HashOperations<String, String, PlayerDraw> hashOperations;
    @Resource
    private PlayerDrawMapper playerDrawMapper;
    @Resource
    private CoreDrawServiceImpl coreDrawService;
    @Resource
    private CoreDrawPoolServiceImpl coreDrawPoolServiceImpl;
    @Resource
    private CoreDrawConfigServiceImpl coreDrawConfigServiceImpl;
    @Resource
    private PlayerHeroServiceImpl playerHeroServiceImpl;
    @Resource
    private PlayerBagServiceImpl accountBagServiceImpl;
    @Resource
    private PlayerSkillServiceImpl accountSkillServiceImpl;

    public Map<String, PlayerDraw> playerDrawMap(Long playerId, Integer type) {
        String Key = "player:" + playerId + ":" + "playerDraw:" + type;
        Map<String, PlayerDraw> entries = hashOperations.entries(Key);
        if (entries.isEmpty()) {
            LambdaQueryWrapper<PlayerDraw> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PlayerDraw::getType, type);
            wrapper.eq(PlayerDraw::getUid, playerId);
            entries = playerDrawMapper.selectList(wrapper).stream().collect(
                    Collectors.toMap(key -> key.getLv() + "", value -> value));
            hashOperations.putAll(Key, entries);
            redisTemplate.expire(Key, 1, TimeUnit.DAYS);
        }
        return entries;
    }

    public void updateById(PlayerDraw entity) {
        int i = playerDrawMapper.updateById(entity);
        String Key = "player:" + entity.getUid() + ":" + "playerDraw:" + entity.getType();
        if (i > 0) {
            hashOperations.put(Key, entity.getLv() + "", entity);
            redisTemplate.expire(Key, 1, TimeUnit.DAYS);
        }
    }

    @Transactional
    public List<?> draw(Long playerId, Integer type, Integer num) {// 总次数
        LambdaQueryWrapper<PlayerDraw> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PlayerDraw::getUid, playerId);
        List<PlayerDraw> playerDraws = playerDrawMapper.selectList(wrapper);
        List<CoreDraw> coreDraws = coreDrawService.listCache();
        if (playerDraws.isEmpty() || playerDraws.size() != coreDraws.size()) {
            coreDraws.forEach(coreDraw -> {
                LambdaQueryWrapper<PlayerDraw> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(PlayerDraw::getUid, playerId);
                wrapper1.eq(PlayerDraw::getType, coreDraw.getType());
                wrapper1.eq(PlayerDraw::getLv, coreDraw.getLv());
                PlayerDraw one = playerDrawMapper.selectOne(wrapper1);
                if (one == null) {
                    PlayerDraw playerDraw = new PlayerDraw();
                    playerDraw.setUid(Long.valueOf(playerId));
                    playerDraw.setType(coreDraw.getType());
                    playerDraw.setLv(coreDraw.getLv());
                    playerDraw.setTime(0L);
                    playerDraw.setTotalTime(0L);
                    playerDrawMapper.insert(playerDraw);
                }
            });
        }

        List<CoreDraw> list = new ArrayList<>();
        CoreDrawConfig coreDrawConfig =
                coreDrawConfigServiceImpl.getCache(Long.valueOf(type));
        List<String> price = Arrays.asList(coreDrawConfig.getPrice(num));
        // 顺序反转
        Collections.reverse(price);

        boolean isPay = false;
        for (String priceInfo : price) {
            String[] split = priceInfo.split("&");
            Long propId = Long.parseLong(split[0]);
            Long needNum = Long.parseLong(split[1]);
            List<PlayerBag> playerBags = accountBagServiceImpl.eqlist(PlayerBag.builder().uid(playerId).corePropId(propId).build());
            PlayerBag accountBag;
            if (playerBags.isEmpty()) {
                continue;
            }
            accountBag = playerBags.get(0);
            Long prePayNum = accountBag.getNum();
            isPay = prePayNum > needNum;// 可支付
            if (isPay) {
                PlayerBag use = accountBagServiceImpl.use(playerId, propId, needNum);
                log.info("玩家{}消耗{}-{}({}->{})", playerId, propId, needNum, prePayNum, use.getNum());
                break;
            }
        }
        if (!isPay) {
            throw new ServiceException("余额不足");
        }

        // 保底
        Map<String, PlayerDraw> playerDrawMap = playerDrawMap(playerId, type);
        String[] times = coreDrawConfig.getTimes();
        boolean isTime = false;
        for (String time : times) {
            String[] split = time.split("&");
            Integer lv = Integer.valueOf(split[0]);
            Integer totalTime = Integer.valueOf(split[1]);
            PlayerDraw playerDraw = playerDrawMap.get(lv + "");
            if (playerDraw == null) {
                break;
            }
            isTime = (playerDraw.getTime() >= totalTime);// 获取保底
            if (isTime) {
                playerDraw.setTime(0L);// 清空当前累计未出货次数
                playerDraw.setTotalTime(playerDraw.getTotalTime() + 1);// 累计获取数量
                updateById(playerDraw);
                // 增加其他稀有度 累计未出货次数
                playerDrawMap.forEach((k, v) -> {
                    if (!Objects.equals(v.getLv(), lv)) {
                        v.setTime(v.getTime() + 1);
                        updateById(v);
                        playerDrawMap.put(k, v);// 更新
                    }
                });

                CoreDraw coreDraw = coreDrawService.getCache(type, lv);
                obtainReward(playerId, type, coreDraw);
                log.info("玩家{}保底次数满足,获取保底奖励{}{}", playerId, coreDraw.getLv(), coreDraw);
                list.add(coreDraw);
                num -= 1;
                log.info("玩家当前抽卡剩余次数{}", num);
            }
        }
        if (!isTime) {
            log.info("玩家{}保底次数不足", playerId);
        }

        ArrayList<Long> rewardIds = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            CoreDraw coreDraw = coreDrawService.draw(type);
            obtainReward(playerId, type, coreDraw);
            list.add(coreDraw);
            rewardIds.add(coreDraw.getCoreDrawPool().getRewardId());
        }


        for (CoreDraw coreDraw : list) {
            Integer lv = coreDraw.getLv();
            PlayerDraw playerDraw = playerDrawMap.get(lv + "");
            if (playerDraw == null) {
                playerDraw = new PlayerDraw();
                playerDraw.setLv(lv);
                playerDraw.setType(type);
                playerDraw.setUid(playerId);
                playerDraw.setTime(0L);
                playerDraw.setTotalTime(0L);
                playerDrawMapper.insert(playerDraw);
                playerDrawMap.put(lv + "", playerDraw);
            }
            playerDraw.setTime(playerDraw.getTime() + 1);
            playerDraw.setTotalTime(playerDraw.getTotalTime() + 1);
            updateById(playerDraw);
        }
        return rewardIds;
    }

    private void obtainReward(Long playerId, Integer type, CoreDraw coreDraw) {
        CoreDrawPool coreDrawPool = coreDrawPoolServiceImpl.draw(coreDraw.getPool());
        coreDraw.setCoreDrawPool(coreDrawPool);
        Long rewardId = coreDrawPool.getRewardId();
        switch (type) {
            case 1:
                PlayerHero accountHero = playerHeroServiceImpl.obtainHero(playerId, rewardId, 1);
                log.info("玩家{}抽卡获得武将{}", playerId, accountHero);
                break;
            case 2:
                PlayerSkill accountSkill = accountSkillServiceImpl.obtainSkill(playerId, rewardId, 1);
                log.info("玩家{}抽卡获得技能{}", playerId, accountSkill);
                break;
            default:
                throw new ServiceException("不支持的抽卡类型");
        }
    }
}
